StackWalker 1.0: Delphi 2.0 debugger helper. Copyright (c) 1996, D.J. Murdoch These units (STAKWALK and STAKLOW) help with the problem of exceptions occurring in the run-time library in Borland's Delphi 2.0: the debugger often can't find where in your code the error was triggered. The problem is that when an exception occurs, the debugger tries to walk up the stack until it finds a return address in your source code. However, sometimes it can't walk up the stack, and so it can't find the error. (This might be related to whether you have stack frames turned on, but sometimes doing that is not enough.) What I did to fix this in StackWalker was to install an exception handler that would look at *every* value on the stack, trying to find one that appears to be a return address to code with source. It does this by reading the .MAP file to figure out source addresses, and then just comparing everything on the stack to those until it turns something up. This procedure is definitely not bulletproof. There are lots of reasons to have addresses on the stack that aren't return addresses; if you do, StackWalker will give false messages. However, getting a few false addresses mixed in with the real ones is better than getting no information at all. To use it: 1. Set the detailed map file linker option on. This is in the Project|Options|Linker page. StackWalker uses the .MAP file to figure out what return addresses correspond to code. If it can't find the .MAP file in the same directory as the executable, or can't find the line number records in the .MAP file, it gives a warning and makes wild guesses, which give so many false alarms that it'll soon convince you to generate the .MAP file. 2. Set the $D+ option on for every unit where you want to see the errors. StackWalker won't show addresses in units compiled $D- (unless you forgot to make the .MAP file). 3. Link one of the StackWalker units into your code. There are 2 ways to do this: a) If you've got a regular Delphi application, then add StakWalk to the project. It will automatically install all the hooks to get things working. OR b) In a console mode application or other application that doesn't use VCL, add StakLow to the project or to a Uses clause somewhere. It will install itself as the default exception handler. (This doesn't work in a VCL application, because the default handler never gets called.) You won't get the helpful dialog that StakWalk gives you, but it should still give you the same information. If you have your own default exception handler, you might find that StakLow messes it up, or doesn't get activated. But if you've got your own exception handler, you're probably clever enough to figure out how to fix this kind of problem. 4. Compile and run your program and do whatever it is that triggers the exception. After the usual unhelpful message pops up telling you that an exception happened somewhere (but not telling you where), hit F9 to continue running. At this point StackWalker will examine the stack and trigger an exception at every place it thinks might be in the call stack. (You'll likely get a few false alarms. If there was a foolproof way to do this, Delphi would do it itself). 5. When you've found the place that really caused the trouble, click Cancel in the StackWalker dialog (or manually change the value of the global variable StopWalker to True) to stop it from walking all the way back up the stack. If you don't do this and let it go too far, it'll eventually trigger an exception at the "Application.Run" line. If you keep going past that, you may find weird behaviour (e.g. I found once that StackWalker got turned off for no apparent reason); I think by that point your program may be messed up, so be careful. You can have a little more control over the behaviour by manually setting some of the global variables in the StakLow unit: WalkerActive: set this to False when you don't need the special handling for future exceptions. StopWalker: set this to True to stop the current walk. ContinueFunc: assign a boolean function to this variable, to replace StakWalk's dialog. It will be called just before the exception is triggered, and should return true if you want another debug exception generated. You can also make a call to WalkStack at any time to trigger a walk through the stack. BUGS: For reasons I don't understand and don't know how to fix, floating point exceptions sometimes mess up StackWalker. You'll just get the regular exception message over and over again, and never find out where it was triggered. If you know how to fix this, please tell me. FILES: This package contains the following files: STAKWALK.TXT: This doc file. STAKWALK.PAS: The high level unit to use to turn on StackWalker. STAKWALK.DFM: The form file for the StackWalker dialog. STAKLOW.PAS: The low level unit used by STAKWALK, or directly if you don't use VCL. PROJECT1.DPR, UNIT1.PAS, UNIT1.DFM: A simple demonstration project. RELEASE HISTORY: Version 0.1: Initial release 0.2: Forced optimization off in StakLow, so test for stack doesn't get optimized away 0.3: Added check for debugger, so you can distribute code to testers but not have the dialog pop up except when they're debugging. 1.0: First public release; same as 0.3. LICENSE: StackWalker is not public domain code. Its copyright belongs to Duncan Murdoch. You are licensed to use it at no charge, but may not sell it or incorporate it into another product without prior written permission. You may not charge more than $1 for the distribution of StackWalker. You may include it in a CDROM compilation provided you charge no more than $1 per package in the compilation. As a courtesy, I would appreciate receiving a copy of any CDROM that includes it, but this is not a legal requirement. I do not offer any guarantee or support for StackWalker. It works at a low level, and there may well be conditions that cause it to crash your program, Delphi, or Windows. If StackWalker helps you so much that you want to show your appreciation in a monetary way, you may send a contribution in any amount to D.J. Murdoch 337 Willingdon Ave. Kingston, Ontario, Canada K7L 4J3 For contributions of $20 (US or Canadian) or more, I'll send you a diskette containing the latest version of StackWalker and a collection of other utilities that I've written. Please make payments by US dollar cheque drawn on a US bank, Canadian dollar cheque drawn on a Canadian bank, or pounds Stirling cheque drawn on a UK bank (equivalent to $20 US, if you want the diskette). Unfortunately, I can't accept credit cards to handle payments from people from other countries. However, I do have an arrangement with the Public Software Library to accept shareware registrations for various programs by credit card, and some of those will get you the disk; write to me for details. Duncan Murdoch dmurdoch@mast.queensu.ca